#include"Sphere.h"
#include"trax.hpp"

namespace AtomTrace{

    Sphere::Sphere():
        _center(0.0f, 0.0f, 0.0f),
        _radius(1.0f),
        _matID(-1),
        _objID(-1)
    {}

    Sphere::Sphere(const Vector3 & iCenter, float iRadius):
        _center(iCenter),
        _radius(iRadius),
        _matID(-1),
        _objID(-1)
    {}

    void Sphere::Set(float cx, float cy, float cz, float iradius)
    {
        _center.Set(cx, cy, cz);
        _radius = iradius;
    }

    void Sphere::Set(const Vector3 & icenter, float iradius)
    {
        _center = icenter;
        _radius = iradius;
    }

    bool Sphere::Intersect(const Ray & iRay, HitRecord & hRec)
    {
        //printf("center[%f, %f, %f]\n", _center[0], _center[1], _center[2]);
        //printf("radius=%f\n", _radius);
        //printf("ray.dir[%f, %f, %f]\n", iRay._dir[0], iRay._dir[1], iRay._dir[2]);
        float a = iRay._dir.LengthSquare();
        float b = (iRay._o - _center).Dot(iRay._dir) * 2.0f;
        float c = (iRay._o - _center).LengthSquare() - _radius*_radius;
        
        float h = b*b - 4.0f*a*c;

        if(h<0.0f)
            return false; // no intersection

        h = sqrt(h);

        float inv2a = 0.5f / a;
        float lroot = (-b + h) * inv2a;
        float sroot = (-b - h) * inv2a;

        if(lroot < 0.0f)
            return false; // all intersection behind the ray

        float res;
        if(sroot < 0.0f) // only positive result matter
        {
            res = lroot;
        }else
            res = sroot;

        if(res < hRec.t){
            hRec.t = res;
            hRec.objID = this->_objID;
            hRec.matID = this->_matID;
            hRec.P = iRay._o + iRay._dir * hRec.t;
            hRec.N = hRec.P - this->_center;
            hRec.N.Normalize();
            return true;
        }else{
            return false;
        }
    }

}// namespace AtomTrace
